package checker

import "kumachan/interpreter/compiler/checker/typsys"


func typeGetRefDef(t typsys.Type) (*typsys.TypeDef, bool) {
	var def, _, ok = typeGetRefDefArgs(t)
	return def, ok
}

func typeGetRefDefArgs(t typsys.Type) (*typsys.TypeDef, ([] typsys.Type), bool) {
	var nested, is_nested = t.(*typsys.NestedType)
	if !(is_nested) { return nil, nil, false }
	var ref, is_ref = nested.Content.(typsys.Ref)
	if !(is_ref) { return nil, nil, false }
	return ref.Def, ref.Args, true
}

func typeDefFindEnumChain(d *typsys.TypeDef, bound *typsys.TypeDef) ([] typsys.CaseInfo, bool) {
	var chain = make([] typsys.CaseInfo, 0)
	for d.Enum != nil {
		chain = append(chain, d.CaseInfo)
		if d.Enum == bound {
			return chain, true
		}
		d = d.Enum
	}
	return nil, false
}

func typeDefFindPathToAncestor(I *typsys.TypeDef, ancestor *typsys.TypeDef, base ([] uint)) ([] uint, bool) {
	for i, parent := range I.Implements {
		var current = make([] uint, len(base), (len(base) + 1))
		copy(current, base)
		current = append(current, uint(i))
		if parent == ancestor {
			return current, true
		} else {
			var path, ok = typeDefFindPathToAncestor(parent, ancestor, current)
			if ok {
				return path, true
			}
		}
	}
	return nil, false
}

func typeDefSubtypingOrderLessThanOperator(u *typsys.TypeDef, v *typsys.TypeDef) bool {
	var box, is_box = u.Content.(*typsys.Box)
	if is_box {
		var u_, ok = typeGetRefDef(box.InnerType)
		if !(ok) { return false }
		if u_ == v {
			return true
		} else {
			return typeDefSubtypingOrderLessThanOperator(u_, v)
		}
	} else {
		return false
	}
}


